Android — 序列化的两种方式
前言
在看一些面试题的时候,竟然把序列化划分为基础知识。真是没接触就不知道它有多简单!本篇就来揭开序列化的神秘面纱,目录如下:
- 序列化是什么?
- 为什么要进行序列化?
- Android中的两种序列化方式概况
- Serializable 和 Parcelable 的区别
- Serializable 的使用
- Parcelable 的使用
- 更多参考
国际惯例,先放张图,QwQ
序列化是什么?
序列化是指把 Java 对象转化为字节序列并存储到一个存储媒介的过程。反之,把字节序列恢复到 Java 对象的过程则称为反序列化。
为什么要序列化?
Java 对象存在的一个前提是 JVM 有在运行。因此,如果 JVM 没有运行或者在其他机器的 JVM 上是不可能获取到指定 Java 对象的,而序列化操作则是把 Java 对象信息保存到存储媒介,可以在以上不可能的情况下仍然可以使用 Java 对象。
所以,序列化的主要作用是:
- 永久保存对象,保存对象的字节序列到本地文件中
- 通过序列化对象在网络中传递对象
- 通过序列化在进程间传递对象
Android中的两种序列化方式概况
在Android开发中,经常需要再多个部件(Activity、Fragement)之间通过 Intent 传递一些数据,如果是一些普通类型的数据可以通过putExtra()进行传递,如果是对象的话就要先进行序列化才能传递了。在Android中有两种序列化的接口,Serializable 和 Parcelable。
Serializable 和 Parcelable 的区别
Serializable 是 Java的序列化接口。特点是简单,直接实现该接口就行了,其他工作都被系统完成了,但是对于内存开销大,序列化和反序列化需要很多的 I/O 流操作。
Parcelable 是Android的序列化方式,主要用于在内存序列化上,采用该方法需要实现该接口并且手动实现序列化过程,相对复杂点。如果序列化到存储设备(文件等)或者网络传输,比较复杂,建议用Serializable 方式。
最大的区别就是存储媒介的不同:Serializable 使用IO读写存储在硬盘上,Parcelable 是直接在内存中读写,内存读写速度远大于IO读写,所以Parcelable 更加高效。Serializable在序列化过程中会产生大量的临时变量,会引起频繁的GC,效率低下。
区别 |
Serializable |
Parcelable |
所属API |
Java API |
Android SDK API |
原理 |
反射,需要大量的I/O操作 |
不需要大量的I/O操作 |
开销 |
大 |
小 |
效率 |
低 |
很高 |
使用场景 |
序列化到本地或者通过网络传输 |
内存序列化 |
Serializable 的使用
使用很简单,只需要实现 Serializable 接口即可。例如:
1 2 3 4 5 6 7 8 9 10 11
| public class StudentBean implements Serializable { private String name; private transient int age; public StudentBean(String name, int age) { this.name = name; this.age = age; } }
|
序列化到本地和反序列:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class TestSer { public static void main(String[] args) throws IOException, ClassNotFoundException { StudentBean bean = readBean(); System.out.println(bean.toString()); } private static StudentBean readBean() throws IOException, ClassNotFoundException { ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("D://addons/bean.txt"))); StudentBean bean = (StudentBean) inputStream.readObject(); return bean; } private static void writeBean() { StudentBean bean = new StudentBean("Omooo", 21); try { ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("D://addons/bean.txt"))); outputStream.writeObject(bean); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
即通过 ObjectOutputStream/ObjectInputStream 实现序列化和反序列。
在Android的运用:
即通过 Intent 传递序列化后对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public void send(View view) { StudentBean user = new StudentBean(); user.setName("Omooo"); user.setAge(20); Intent intent = new Intent(this, SecondActivity.class); intent.putExtra("user", user); //传输的第二种方法:Intent利用putExtras(注意s)传入bundle Bundle bundle = new Bundle(); bundle.putSerializable("user", user); intent.putExtras(bundle); */ startActivity(intent); }
|
在跳转的Activity:
1 2 3
| Intent intent = getIntent(); StudentBean user = (StudentBean) intent.getSerializableExtra("user"); mView.setText(user.getName() + " " + user.getAge());
|
注意:
- 序列化前、后的对象内容完全一致,但不是同一个对象
- 静态成员变量属于类,不会参与序列化过程
- 用 transient 关键字修饰的成员变量不参与序列化过程
- 可重写 writeObject()、readObject()来改变系统默认的序列化过程
- 可使用此类的子类 Externalizable 对序列化进行自定义控制
Parcelable 的使用
- 继承 Parcelable 接口
- 重写 describeContents()、writeToParcel()方法(Implement methods)
- 添加 Parcel形参的构造函数,公有静态常量CREATOR(Add Parcelable Implementation)
Android Studio 插件:Android Parcelable code generator
写完实体类,Generate界面(Alt + Insert键)选择Parcelable一键生成。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class User implements Parcelable { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } public User() { } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.name); dest.writeInt(this.age); } protected User(Parcel in) { this.name = in.readString(); this.age = in.readInt(); } public static final Creator<User> CREATOR = new Creator<User>() { @Override public User createFromParcel(Parcel source) { return new User(source); } @Override public User[] newArray(int size) { return new User[size]; } }; }
|
在传递序列化后对象的时候和用Serializable一样,唯一不同的就是取对象的时候是:
1 2 3
| Intent intent = getIntent(); User user = intent.getParcelableExtra("user"); mView.setText(user.getName() + "\n" + user.getAge());
|
也就是 getSerializableExtra / getParcelableExtra 的区别。
更多参考
https://www.jianshu.com/p/74a70fae99fb
https://www.jianshu.com/p/ed01c4b7a14d
https://www.jianshu.com/p/287acb9e396f